package com.example.dictionary.repository;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.rocksdb.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

/**
 * RocksDB Repository for high-performance key-value storage
 */
@Repository
public class RocksDbRepository {
    
    private static final Logger log = LoggerFactory.getLogger(RocksDbRepository.class);
    
    private RocksDB db;
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    @Value("${dictionaries.storage.rocksdb-path:./data/rocksdb}")
    private String rocksdbPath;
    
    @PostConstruct
    public void init() {
        try {
            RocksDB.loadLibrary();
            
            Options options = new Options();
            options.setCreateIfMissing(true);
            options.setMaxOpenFiles(1000);
            options.setWriteBufferSize(64 * 1024 * 1024); // 64MB
            options.setMaxWriteBufferNumber(3);
            options.setTargetFileSizeBase(64 * 1024 * 1024); // 64MB
            
            // 创建目录
            File dbDir = new File(rocksdbPath);
            if (!dbDir.exists()) {
                dbDir.mkdirs();
            }
            
            db = RocksDB.open(options, rocksdbPath);
            log.info("RocksDB initialized at: {}", rocksdbPath);
            
        } catch (RocksDBException e) {
            log.error("Failed to initialize RocksDB", e);
            throw new RuntimeException("RocksDB initialization failed", e);
        }
    }
    
    @PreDestroy
    public void close() {
        if (db != null) {
            db.close();
            log.info("RocksDB closed");
        }
    }
    
    /**
     * 存储键值对
     */
    public void put(String key, Object value) {
        try {
            String jsonValue = objectMapper.writeValueAsString(value);
            db.put(key.getBytes(StandardCharsets.UTF_8), jsonValue.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error("Failed to put key: {}", key, e);
            throw new RuntimeException("Failed to store data", e);
        }
    }
    
    /**
     * 获取值（JSON 反序列化）
     */
    public <T> Optional<T> get(String key, Class<T> clazz) {
        try {
            byte[] value = db.get(key.getBytes(StandardCharsets.UTF_8));
            if (value != null) {
                // 如果是 byte[] 类型，直接返回
                if (clazz == byte[].class) {
                    @SuppressWarnings("unchecked")
                    T result = (T) value;
                    return Optional.of(result);
                }
                // 否则使用 JSON 反序列化
                String jsonValue = new String(value, StandardCharsets.UTF_8);
                return Optional.of(objectMapper.readValue(jsonValue, clazz));
            }
            return Optional.empty();
        } catch (Exception e) {
            log.error("Failed to get key: {}", key, e);
            return Optional.empty();
        }
    }
    
    /**
     * 获取原始字节数组
     */
    public Optional<byte[]> getBytes(String key) {
        try {
            byte[] value = db.get(key.getBytes(StandardCharsets.UTF_8));
            return value != null ? Optional.of(value) : Optional.empty();
        } catch (RocksDBException e) {
            log.error("Failed to get bytes for key: {}", key, e);
            return Optional.empty();
        }
    }
    
    /**
     * 存储原始字节数组
     */
    public void putBytes(String key, byte[] value) {
        try {
            db.put(key.getBytes(StandardCharsets.UTF_8), value);
        } catch (RocksDBException e) {
            log.error("Failed to put bytes for key: {}", key, e);
            throw new RuntimeException("Failed to store bytes", e);
        }
    }
    
    /**
     * 删除键
     */
    public void delete(String key) {
        try {
            db.delete(key.getBytes(StandardCharsets.UTF_8));
        } catch (RocksDBException e) {
            log.error("Failed to delete key: {}", key, e);
            throw new RuntimeException("Failed to delete data", e);
        }
    }
    
    /**
     * 检查键是否存在
     */
    public boolean exists(String key) {
        try {
            byte[] value = db.get(key.getBytes(StandardCharsets.UTF_8));
            return value != null;
        } catch (RocksDBException e) {
            log.error("Failed to check existence of key: {}", key, e);
            return false;
        }
    }
    
    /**
     * 获取所有键
     */
    public java.util.List<String> getAllKeys() {
        java.util.List<String> keys = new java.util.ArrayList<>();
        try (RocksIterator iterator = db.newIterator()) {
            iterator.seekToFirst();
            while (iterator.isValid()) {
                keys.add(new String(iterator.key(), StandardCharsets.UTF_8));
                iterator.next();
            }
        }
        return keys;
    }
}
